/*
 * onViewport jQuery plugin
 * version 0.1
 *
 *
 * Manel R. Dom?nech
 * mdomenech@onestic.com
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://onestic.com
 *
 */
 
 ;(function($) {

 if ($.fn.imageLoad == undefined) {
	$.fn.imageLoad = function(fn){
		this.load(fn);
		this.each( function() {            
			if ( this.complete && this.naturalWidth !== 0 ) {
				$(this).trigger('load');
			}
		});
	}
}
 
$.fn.onStyles = function() {
	/*
	var attr = ['font-family','font-size','font-weight','font-style','color',
        'text-transform','text-decoration','letter-spacing','word-spacing',
        'line-height','text-align','vertical-align','direction','background-color',
        'background-image','background-repeat','background-position',
        'background-attachment','opacity','width','height','top','right','bottom',
        'left','margin-top','margin-right','margin-bottom','margin-left',
        'padding-top','padding-right','padding-bottom','padding-left',
        'border-top-width','border-right-width','border-bottom-width',
        'border-left-width','border-top-color','border-right-color',
        'border-bottom-color','border-left-color','border-top-style',
        'border-right-style','border-bottom-style','border-left-style','position',
        'display','visibility','z-index','overflow-x','overflow-y','white-space',
        'clip','float','clear','cursor','list-style-image','list-style-position',
        'list-style-type','marker-offset'];
	*/
	
	var attr = ['float', 'clear', 'top','right','bottom',
        'left','margin-top','margin-right','margin-bottom','margin-left',
        'padding-top','padding-right','padding-bottom','padding-left',
		'border-left-width',
		'border-left-style',
		'border-left-color',
		'border-right-width',
		'border-right-style',
		'border-right-color',
		'border-top-width',
		'border-top-style',
		'border-top-color',
		'border-bottom-width',
		'border-bottom-style',
		'border-bottom-color'
		];
		
		var len = attr.length, obj = {};
		for (var i = 0; i < len; i++) 
			obj[attr[i]] = jQuery.fn.css.call(this, attr[i]);
		return obj;
}
 
if (document.console == undefined) {	
	document.console = {
		log: function(str) {
			$('body').prepend("<span>str</span>");			
		}
	}
}


///////////////////////////////////////////////////////////////////////////////
// onViewport function
///////////////////////////////////////////////////////////////////////////////


$.onViewport = function (el, settings, inheritStyles) {
	
	if (inheritStyles == undefined) inheritStyles = true;
	
	var _instance = this;
	
	var $el = $(el);
	
	/*
	setTimeout(function() {
		$overlay.show();
		$el.load(function(e) { $overlay.hide(); }).attr('src', 'http://indufex.com/ups/INDUFEX 12.jpg');
		return false;
	}, 5000);
	*/
	
	var $viewport, $canvas, $layers, $overlay;
	
	var status = {
		scale: 1,
		o: false,
		level: 0
	}
	
	var _busy = 0;
	
	function event(e) {
		
		var o = $viewport.offset({scroll: false});
		var oc = $canvas.offset({scroll: false});
		var px = e.pageX == undefined?e.clientX:e.pageX;
		var py = e.pageY == undefined?e.clientY:e.pageY;
		return {
			click: {
				pageX: px,
				pageY: py,
				vpx: px - o.left,
				vpy: py - o.top,
				cx: px - oc.left,
				cy: py - oc.top
			}
		}
	}
	
	function prepare() {
		var w = $el.width();
		var h = $el.height();
		
		var elStyles = $el.onStyles();
		
		$el.css({
			margin: 0,
			padding: 0,
			top: 'auto',
			right: 'auto',
			bottom: 'auto',
			left: 'auto',
			border: 'none'
		});
		
		//var $expendables = $('.expendable').clone();
		
		$canvas = $("<div>")
			.attr('class', 'on-canvas');
				
		$viewport = $("<div>")	
			.attr('class', 'on-viewport')			
			.css({width: w, height: h});
			
		$layers = $("<div>").addClass('on-layers');
		
		$canvas = $el.wrap($canvas).parent().prepend($layers);
		
		$viewport = $canvas.wrap($viewport).parent();
		
		if (inheritStyles) $viewport.css(elStyles);
		
		//$viewport.css(elStyles)
		
		$overlay = $('<div>').addClass('on-overlay');
		//.append($('<img>').attr('src', 'css/onimage/images/ajax-loader.gif'));
		
		$viewport.append($overlay);
		
		
		//$canvas.append($expendables);
		
		if (el.tagName == 'IMG') $el.removeAttr('width').removeAttr('height');

		$('img:first', $canvas).imageLoad(function() {			
			$(this).unbind('load');
			setTimeout(function() {
				scale(1);
				scaleToFit(1);
				centerh();
				centerv();
				
				for(var i = 0; i < 20; i++) {
					//addMarker(Math.random()*w, Math.random()*h);
				}

				//addMarker(500, 375);
				
				$el.show();
			}, 10);
			
		});
		
	}
	
	function addMarker(settings) {
                if (!settings) settings = {};
                if (!settings.update) settings.update = function() {};
                if (!settings.create) settings.create = function() {};
                var x = settings.x;
                var y = settings.y;
		//console.log('marker at '+x+', '+y);
		var marker = $('<span>').addClass('on-marker-wrapper');
		var markerHandler = $('<span>').addClass('on-marker').appendTo(marker);
		
		marker.css({
			top: y+'px',
			left: x+'px'
		});
		
		markerHandler.mousedown(function(e0) {
		//console.log('marker mousedown');
			var moved = false;
			marker.moved = moved;
			e0.preventDefault();
			e0.stopPropagation();
			e0.stopImmediatePropagation();
			var $marker = marker;
			var o = $marker.position();
			$(document).mousemove(function(e1) {
				//console.log('marker document mousemove');
				e1.preventDefault();
				moved = true;
				marker.moved = moved;
				var dx = e1.pageX - e0.pageX;
				var dy = e1.pageY - e0.pageY;
				$marker.css({
					top: (o.top + dy)+'px',
					left: (o.left + dx)+'px'
				});				
			}).mouseup(function(e1) {
                            if (moved) marker.removeData('_on');
                            else {
                                if (typeof(settings.click) == 'function') {
                                    settings.click($marker);
                                }
                            }
                            settings.update(marker);
                            $(this).unbind("mousemove").unbind("mouseup").unbind("mouseout");
			});
			
			$marker.click(function(e) {
                            e.stopPropagation();
                            if (moved) return;
                            //console.log('click on marker!');
                            //$marker.unbind('click');
			});
			
			return false;
		});
		$layers.append(marker);

                settings.create(marker);
                
		return marker;
	}
	
	function addArea(s) {
		var $area = $('<div>').addClass('on-area').css({
			top: s.y1+'px',
			left: s.x1+'px',
			width: s.width+'px',
			height: s.height+'px'
		}).appendTo($layers);
		
		return $area;
	}
	
	function id(v) {return v;}
	
	
	function _start() {
		_busy++;
		return _instance;
	}
	
	function _end() {
		_busy--;
		if (_busy == 0) {
			_update();			
		}
		return _instance;
	}
	
	function _update() {
            var p = $canvas.position();
            var x1 = -p.left;
            var y1 = -p.top;
            var x2 = x1 + $viewport.width();
            var y2 = y1 + $viewport.height();


            if (settings.callback) {
                   settings.callback(x1, y1, x2, y2, status.scale);
            }

            //console.log(x1+', '+y1+', '+x2+', '+y2);

            //settings.callback(x1 / status.scale, y1 / status.scale, x2 / status.scale, y2 / status.scale);
	}
	
	
	function _scale(els, k, rel, depth) {
		__scale(els, k, rel, depth);
		
		var sel = 0;
		if (settings.scales) {		
			for(var i in settings.scales) {				
				var s = settings.scales[ i ];
				if (s.scale > k) break;
				sel = i;
			}
			
			if (sel != status.level) {
				status.level = sel;				
				$overlay.show();
				//console.log('changed to '+settings.scales[ sel ].scale+' ('+k+')');
				$el.load(function(e) { $overlay.hide(); }).attr('src', settings.scales[ sel ].src);
			}
		}
	}
	
	function __scale(els, k, rel, depth) {
		if (depth > 5) return;
		depth = depth || 0;
		rel = rel || 0;		
		var s = status.scale;
		
		$(els).each(function() {
			var el = $(this);
			
			var i = el.data('_on');
			var x, y, w, h, ow, oh, dw, dh;
			if (i == undefined) {
				var pos = el.position();

				var ow0 = el.outerWidth();
				var oh0 = el.outerHeight();
				var w0 = el.width();
				var h0 = el.height();
				
				
				i = {x: pos.left / s, y: pos.top / s, w: w0 / s, h: h0 / s, ow: ow0 / s, oh: oh0 / s};
				i.dw = ow0 - w0;
				i.dh = oh0 - h0;
				el.data('_on', i);
			}
			
			var f = Math.ceil;
			//var f = id;
			
			var _w = f(i.ow * k - i.dw);
			var _h = f(i.oh * k - i.dh);
			var _x = f(i.x * k);
			var _y = f(i.y * k);
			
			el.css({
				width: _w+'px',
				height: _h+'px',
				left: _x+'px',
				top: _y+'px'
			});
		
			if (!el.hasClass('on-marker-wrapper')) __scale($(el).children(), k, rel, depth+1);
		});
		
		
	}
	
	function _contentBounds(els, bounds) {		
		bounds = bounds || {};
		
		$(els).each(function() {
			
			var p0 = $(this).offset({scroll: false});
			var p1right = p0.left + $(this).outerWidth();
			var p1bottom = p0.top + $(this).outerHeight();
			
			//alert(this.tagName+', '+p0.left+', '+p0.top+', '+p1right+', '+p1bottom);
			
			if (bounds.left == undefined || p0.left < bounds.left) bounds.left = p0.left;
			if (bounds.right == undefined || p1right > bounds.right) bounds.right = p1right;
			if (bounds.top == undefined || p0.top < bounds.top) bounds.top = p0.top;
			if (bounds.bottom == undefined || p1bottom > bounds.bottom) bounds.bottom = p1bottom;
			
			_contentBounds($(this).children(), bounds);
		});
		
		return bounds;
	}
	
	function contentBounds() {
		return _contentBounds($canvas.children());
	}
	
	function contentSize() {
		var bounds = _contentBounds($canvas.children());		
		var o = $viewport.offset({scroll: false});
		return {x: bounds.left - o.left - 1, y: bounds.top - o.top - 1, w: bounds.right - bounds.left, h: bounds.bottom - bounds.top}
	}
	
	function origin(x, y, scale) {
		if (x === null || x === false) {
			status.o = false;
			return;
		}
		
		status.o = {
			x: x,
			y: y,
			scale: scale
		}
	}
	
	function originvp(x, y, scale) {
		if (x === null || x === false) {
			status.o = false;
			return;
		}
		
		
		//console.log(x+', '+y+', '+scale);
		
		var o = $canvas.position();
		var xc0 = x - o.left;
		var yc0 = y - o.top;
		origin(xc0, yc0, scale);
	}
	
	
	function scaleTo(k, x, y) {		
		
		//console.log(status.o);
		
		_start();
		
		var k0 = status.o && status.o.scale?status.o.scale:status.scale;		
		x = x || 0;
		y = y || 0;		
		
		var d = k / k0;
		
		var xc0 = x;
		var yc0 = y;
		var xc1 = xc0 * (d);
		var yc1 = yc0 * (d);
		var dx = -(xc1 - xc0);
		var dy = -(yc1 - yc0);
		
		if (status.o) {
			translateTo(status.o.x + dx, status.o.y + dy);
		} else {
			var o = $canvas.position();
			translateTo(o.left + dx, o.top + dy);
		}
		
		_scale($canvas.children(), k);
		
		status.scale = k;
		
		_end();
		
		return _instance;
	}
	
	function scaleTovp(k, x, y) {
		_start();
		
		var d = k / status.scale;		
		if (x != undefined && y != undefined) {		
			var o = $canvas.position();
			
			var xc0 = x - o.left;
			var yc0 = y - o.top;			
			var xc1 = xc0 * (d);
			var yc1 = yc0 * (d);			
			var dx = -(xc1 - xc0);
			var dy = -(yc1 - yc0);
			
			
			translate(dx, dy);
		} 
		_scale($canvas.children(), k);
		
		status.scale = k;
		
		_end();
		return _instance;
	}
	
	function scale(_k, x, y) {		
		_start();
		k = status.scale * _k;		
		_scale($canvas.children(), k, 1);
		if (x != undefined && y != undefined) {
			translate(-x * (_k - 1), -y * (_k - 1));
		}		
		status.scale = k;
		_end();		
		return _instance;
	}
	
	function scalevp(_k, x, y) {
		_start();
		k = status.scale * _k;	
		_scale($canvas.children(), k, 1);
		if (x != undefined && y != undefined) {
			var o = $canvas.position();
			var _x = x - o.left;
			var _y = y - o.top;		
			translate(-_x * (_k - 1), -_y * (_k - 1));
		}		
		status.scale = k;
		_end();
		return _instance;
	}
	
	function translateTo(x, y) {
		_start();
		var css = {};
		if (x != null) css.left = x+'px';
		if (y != null) css.top = y+'px';
		$canvas.css(css);
		_end();
	}
	
	function translate(x, y) {		
		_start();
		var position = $canvas.position();
		translateTo(position.left + x, position.top + y);
		_end();
		return _instance;
	}
	
	function scaleToFit(zc) {
		_start();
		zc = zc || 0;
		var s0 = {w: $viewport.width(), h: $viewport.height()};
		var s1 = contentSize();		
		var kw = s0.w/s1.w;
		var kh = s0.h/s1.h;		
		
		if (kw < kh) zc?scale(kh):scale(kw);
		else zc?scale(kw):scale(kh);
		_end();
		return _instance;
		
	}
	
	
	function centerh() {
		_start();
		var s0 = {w: $viewport.width(), h: $viewport.height()};
		var s1 = contentSize();		
		translateTo((s0.w - s1.w) / 2, null);
		_end();
		return _instance;
	}
	
	function centerv() {
		_start();
		var s0 = {w: $viewport.width(), h: $viewport.height()};
		var s1 = contentSize();		
		translateTo(null, (s0.h - s1.h) / 2);
		_end();
		return _instance;
	}
	
	
	this.translate = translate;
	this.translateTo = translateTo;
	
	this.scale = scale;
	this.scalevp = scalevp;
	
	this.scaleTo = scaleTo;	
	this.scaleTovp = scaleTovp;	
	
	this.scaleToFit = scaleToFit;
	
	this.centerh = centerh;
	this.centerv = centerv;
	
	this.origin = origin;
	this.originvp = origin;
	
	this.contentSize  = contentSize;
	
	this.viewport = function() { return $viewport; }
	this.canvas = function() { return $canvas; }
	this.status = function() { return status; }
	
        this.settings = function(s) { settings = s; }

	this._start = _start;
	this._end = _end;
	
	this.event = event;
	
	this.addArea = addArea;
	this.addMarker = addMarker;
	
	prepare();
}


///////////////////////////////////////////////////////////////////////////////
// jQuery onViewport DOM extension
///////////////////////////////////////////////////////////////////////////////


$.fn.extend({
	onViewport: function(settings, inheritStyles) {
		settings = settings || {};
		
		var handlers = [];
		
		this.each(function () {
			if ($(this).data('onViewport'))
				$(this).data('onViewport').settings(settings);		
			else {
				$(this).data('onViewport', new $.onViewport(this, settings, inheritStyles));
				handlers.push($(this).data('onViewport'));
			}
        });
		
		if (handlers.length == 1) return handlers[ 0 ];
		return handlers;
	}
});
    
// End the closure
})(jQuery);